# -*- coding: utf-8 -*-
#

import os
import re
import numpy as np
import pandas as pd

from .backend import DataBackend
from ..utils import get_date_from_int, get_str_date_from_int, get_int_date, convert_date_to_int, convert_dt_to_int

from functools import lru_cache
from datetime import date, datetime, timedelta

# 交易所映射
Exchange_JQ2VT = {
    "CCFX": "CFFEX",
    "XSGE": "SHFE",
    "XZCE": "CZCE",
    "XDCE": "DCE",
    "XINE": "INE",
    "GFEX": "GFEX",
    "XSHG": "SSE",
    "XSHE": "SZSE"
}

def is_cn_future_id(book_id):
    if re.match("[a-zA-Z]{1,2}[0-9]{2,4}", book_id) is None:
        return False
    return True

def normalize_symbol(symbol, exchange):
    # 正常国内期货代码
    if len(symbol) <= 6 and is_cn_future_id(symbol):
        exchange = Exchange_JQ2VT[exchange] if exchange in Exchange_JQ2VT else exchange
        # 大小写敏感
        if exchange in ("DCE","SHFE","INE","GFEX"):
            symbol = symbol.lower()
        elif exchange in ("CZCE",) and '9999' not in symbol and '8888' not in symbol and '7777' not in symbol and '6666' not in symbol:
            symbol = symbol[:2] + symbol[-3:]
    else:
        # 自定义期货指数
        if symbol.startswith('QHZS'):
            symbol = symbol
    return symbol


def extr_symbol_code(sys_code):
    """"""
    if sys_code[-4:] in ('.USD', '.HKD', '.JPY', '.CAD'):
        return sys_code
    else:
        if '.' in sys_code:
            sys_list = sys_code.split('.')
            if len(sys_list) == 2:
                symbol, exchange = sys_list[0], sys_list[1]
            else:
                symbol, exchange = '.'.join(sys_list[:-1]), sys_list[-1]
            symbol = normalize_symbol(symbol, exchange)
        else:
            symbol = sys_code
        return symbol
    

class DataplatBackend(DataBackend):
    """
    数据中台通道，目前仅支持分钟，日，周数据
    """
    # 保证指标完整，附加的周期数
    add_bar_count = 0
    # 所以支持的周期频率
    all_freq_list = ("M", "W", "1d", "1m", "5m", "10m", "15m", "30m", "60m", "30s", "15s")
    all_columns = ['order_book_id', 'datetime', 'open', 'high', 'low', 'close', 'volume', 'turnover', 'open_interest']
    #
    def __init__(self, data_source):
        """"""
        self._inited = False
        self._datetime = None
        # 默认数据源
        self._ds = data_source


    def get_bar_history(self, sys_code, end_dt, interval, start_dt=None):
        """
        :param order_book_id: e.g. 000002.XSHE
        :param start: 20160101
        :param end: 20160201
        :returns:
        :rtype: numpy.rec.array
        """
        assert interval in self.all_freq_list
        # 
        if start_dt is None:
            start_dt = end_dt
        else:
            start_dt = start_dt
        # 平衡性能和长EMA指标连续性
        if self.add_bar_count >= 720:
            mult = 20
        elif self.add_bar_count >= 480:
            mult = 15
        elif self.add_bar_count >= 240:
            mult = 10
        elif self.add_bar_count >= 120:
            mult = 5
        else:
            mult = 3
        # 历史数据，根据周期向前推几天
        if interval == '1d':
            freq = '1d'
            start_dt = start_dt - timedelta(days=150*mult)
        elif interval == 'W':
            freq = 'W'
            start_dt = start_dt - timedelta(days=150*mult*7)
        elif interval == 'M':
            freq = 'M'
            start_dt = start_dt - timedelta(days=150*mult*31)
        elif interval == '60m':
            freq = '60m'
            start_dt = start_dt - timedelta(days=60+60*mult)
        elif interval == '30m':
            freq = '30m'
            start_dt = start_dt - timedelta(days=30+30*mult)
        elif interval == '15m':
            freq = '15m'
            start_dt = start_dt - timedelta(days=15+15*mult)
        elif interval == '10m':
            freq = '10m'
            start_dt = start_dt - timedelta(days=15+10*mult)
        elif interval == '5m':
            freq = '5m'
            start_dt = start_dt - timedelta(days=15+5*mult)
        elif interval == '1m':
            freq = '1m'
            start_dt = start_dt - timedelta(days=15)
        else:
            freq = interval
            start_dt = start_dt - timedelta(days=7)
        #
        symbol = extr_symbol_code(sys_code)
        data_bar = self._ds.get_realtime_price(order_book_ids=symbol, start_date=start_dt, end_date=end_dt, frequency=freq)
        # 判断数据是否为空
        if data_bar is not None and len(data_bar) > 0:
            his_df = data_bar.reset_index()
            # 兼容成交额名称，'total_turnover'和'turnover'
            if 'turnover' not in his_df:
                if 'total_turnover' in his_df:
                    his_df['turnover'] = his_df['total_turnover']
                else:
                    his_df['turnover'] = 0.0
            print(symbol, start_dt, end_dt, interval, len(his_df), his_df.iloc[-1].datetime)
        else:
            his_df = pd.DataFrame(columns=self.all_columns)
            print(symbol, start_dt, end_dt, interval, None)
        # 
        return his_df


    @lru_cache(maxsize=1)
    def get_price(self, order_book_id, start, end, freq):
        """
        :param order_book_id: e.g. 000002.XSHE
        :param start: 20160101
        :param end: 20160201
        :returns:
        :rtype: numpy.rec.array
        """
        assert freq in self.all_freq_list

        start = get_date_from_int(start) if start is not None else start
        end = get_date_from_int(end)
        # 根据频率截取数据
        his_df = self.get_bar_history(order_book_id, end, freq, start_dt=start)
        his_df['datetime'] = his_df['datetime'].apply(lambda x: convert_dt_to_int(x))
        #
        bars = his_df.to_records()

        if bars is None or len(bars) == 0:
            raise KeyError("empty bars {}".format(order_book_id))

        self._datetime = bars["datetime"]
        return bars

    @lru_cache()
    def get_order_book_id_list(self, date=None):
        """获取所有的
        """
        date = get_date_from_int(date) if date is not None else date
        order_book_id_list = sorted(self._ds.all_instruments_zt(s_type='stock', date=date)['sys_code'].tolist())
        return order_book_id_list

    @lru_cache()
    def get_trading_dates(self, start, end):
        """获取所有的交易日

        :param start: 20160101
        :param end: 20160201
        """
        dates = self._ds.get_trading_dates(start, end)
        trading_dates = [get_int_date(date) for date in dates]
        return trading_dates
    
    @lru_cache()
    def get_previous_trading_date(self, start):
        """获取所有的交易日

        :param start: 20160101
        """
        trading_date = self._ds.get_previous_trading_date(start)
        trading_date = get_int_date(trading_date if trading_date else start)
        return trading_date
